#include "proc.h"
#include <elf.h>
#include "fs.h"

#ifdef __ISA_AM_NATIVE__
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#endif

size_t ramdisk_read(void *buf, size_t offset, size_t len);
Elf_Phdr  pheader[8];


static uintptr_t loader(PCB *pcb, const char *filename) {
  // void* buf =(void*)APP_START_ADDR;
  Elf_Ehdr  header;
  // uintptr_t entry = (uintptr_t)NULL;

  int loadfd = fs_open(filename,0,0);

  if(loadfd == -1) 
    panic("load init pro erro,it's not exist");

  fs_read(loadfd,&header,sizeof(header));
  if(header.e_ident[0] != 0x7F || header.e_ident[1] != 0x45 || 
     header.e_ident[2] != 0x4c  || header.e_ident[3] != 0x46) {
    printk("ELF File erro\n");
    return 0;
  }
  
  fs_lseek(loadfd,header.e_phoff,SEEK_SET);
  fs_read(loadfd,pheader,sizeof(pheader)*header.e_phnum);
  
  for (int i = 0; i < header.e_phnum; i++){
    if(pheader[i].p_type == PT_LOAD){
      // ramdisk_read((void*)pheader[i].p_paddr, pheader[i].p_offset, pheader[i].p_filesz);
      fs_lseek(loadfd,pheader[i].p_offset,SEEK_SET);
      fs_read(loadfd,(void*)pheader[i].p_paddr,pheader[i].p_filesz);
      memset((void*)(pheader[i].p_paddr+pheader[i].p_filesz),0,pheader[i].p_memsz-pheader[i].p_filesz);
    }
  }
  // ramdisk_read(&header, 0, sizeof(header));

  // if(header.e_ident[0] != 0x7F || header.e_ident[1] != 0x45 || 
  //    header.e_ident[2] != 0x4c  || header.e_ident[3] != 0x46) {
  //   printk("ELF File erro\n");
  //   return 0;
  // }
  // ramdisk_read(pheader, header.e_phoff, sizeof(pheader)*header.e_phnum);
  // // printf("p off : %d\n",header.e_phoff);
  // // printf("section off : %d\n",header.e_shoff);
  // //load segment
  // for (int i = 0; i < header.e_phnum; i++){
  //   // printf("P offset : %x , P addr : %x\n",pheader[i].p_offset,pheader[i].p_paddr);
  //   // entry = pheader[i].p_type == PT_LOAD && (pheader[i].p_flags & PF_X) ? pheader[i].p_paddr : entry;
  //   if(pheader[i].p_type == PT_LOAD){
  //     ramdisk_read((void*)pheader[i].p_paddr, pheader[i].p_offset, pheader[i].p_filesz);
  //     memset((void*)(pheader[i].p_paddr+pheader[i].p_filesz),0,pheader[i].p_memsz-pheader[i].p_filesz);
  //   }
  // }

  return header.e_entry;
}

void naive_uload(PCB *pcb, const char *filename) {
  // int _protect(_AddressSpace *as);
  uintptr_t entry = loader(pcb, filename);
  if(entry == 0) {
    Log("entry = %x is illegal", entry);
    return;  
  }
  Log("Jump to entry = %x", entry);
  ((void(*)())entry) ();
}

void context_kload(PCB *pcb, void *entry) {
  _Area stack;
  stack.start = pcb->stack;
  stack.end = stack.start + sizeof(pcb->stack);

  pcb->cp = _kcontext(stack, entry, NULL);
}

void context_uload(PCB *pcb, const char *filename) {
  _protect(&pcb->as);
  uintptr_t entry = loader(pcb, filename);

  _Area stack;
  stack.start = pcb->stack;
  stack.end = stack.start + sizeof(pcb->stack);

  pcb->cp = _ucontext(&pcb->as, stack, stack, (void *)entry, NULL);
}
